/**
 * @file release_benchmark.cpp
 * @brief 内存池性能基准测试程序
 * 
 * @details 该程序用于测试和比较不同类型内存池实现的性能，
 * 包括原始内存池（MemPool）和优化版内存池（OptMemPool）。
 * 通过测量分配和释放内存的CPU时钟周期数来评估性能。
 */

#include "common/mem_pool.h"
#include "common/opt_mem_pool.h"
#include "common/perf_utils.h"

#include "exchange/market_data/market_update.h"

/**
 * @brief 测量内存池性能的函数
 * 
 * @tparam T 内存池类型，可以是MemPool或OptMemPool
 * @param mem_pool 内存池对象指针
 * @return size_t 每个操作（分配或释放）的平均CPU时钟周期数
 * 
 * @details 该函数对指定类型的内存池进行性能测试，通过重复分配和释放内存块，
 * 测量每个操作所需的CPU时钟周期数。使用rdtsc（Read Time-Stamp Counter）指令获取
 * 高精度的CPU时钟计数。最终返回所有操作的平均时钟周期数。
 */
template<typename T>
size_t benchmarkMemPool(T *mem_pool) {
  /**
   * @brief 测试循环次数
   * 
   * @details 定义每个测试运行的外层循环次数，设置为100,000次以确保测试结果的统计显著性。
   */
  constexpr size_t loop_count = 100000;
  
  /**
   * @brief 累计的CPU时钟周期数
   * 
   * @details 用于累计所有内存分配和释放操作的CPU时钟周期数，最终将除以操作数量得到平均值。
   */
  size_t total_rdtsc = 0;
  
  /**
   * @brief 分配对象数组
   * 
   * @details 用于存储从内存池分配的对象指针，大小为256，这意味着每次外层循环将分配和释放256个对象。
   */
  std::array<Exchange::MDPMarketUpdate*, 256> allocated_objs;

  /**
   * @brief 执行测试循环
   * 
   * @details 外层循环执行指定次数，每次循环分配和释放一组对象，并测量每个操作的执行时间。
   */
  for (size_t i = 0; i < loop_count; ++i) {
    /**
     * @brief 内存分配循环
     * 
     * @details 从内存池分配指定数量的对象，并测量每个分配操作的时钟周期数。
     */
    for(size_t j = 0; j < allocated_objs.size(); ++j) {
      const auto start = Common::rdtsc();
      allocated_objs[j] = mem_pool->allocate();
      total_rdtsc += (Common::rdtsc() - start);
    }
    
    /**
     * @brief 内存释放循环
     * 
     * @details 释放前面分配的所有对象，并测量每个释放操作的时钟周期数。
     */
    for(size_t j = 0; j < allocated_objs.size(); ++j) {
      const auto start = Common::rdtsc();
      mem_pool->deallocate(allocated_objs[j]);
      total_rdtsc += (Common::rdtsc() - start);
    }
  }

  /**
   * @brief 计算并返回平均时钟周期数
   * 
   * @details 将总时钟周期数除以操作总数（外层循环次数 * 每次分配的对象数量），
   * 得到每个操作（分配或释放）的平均时钟周期数。
   */
  return (total_rdtsc / (loop_count * allocated_objs.size()));
}

/**
 * @brief 程序的主函数
 * 
 * @param int 未使用的命令行参数数量
 * @param char** 未使用的命令行参数数组
 * @return int 程序退出状态码
 * 
 * @details 主函数测试两种不同的内存池实现（原始版和优化版）的性能，
 * 并输出每种实现的平均操作时钟周期数。两种实现都使用相同的初始容量（512）
 * 进行测试，以确保比较的公平性。
 */
int main(int, char **) {
  /**
   * @brief 测试原始版内存池（MemPool）
   * 
   * @details 创建原始版内存池实例，初始容量为512个对象，运行基准测试，
   * 并输出每个操作的平均时钟周期数。使用若干作用域确保内存池对象
   * 在测试完成后被自动释放。
   */
  {
    Common::MemPool<Exchange::MDPMarketUpdate> mem_pool(512);
    const auto cycles = benchmarkMemPool(&mem_pool);
    std::cout << "ORIGINAL MEMPOOL " << cycles << " CLOCK CYCLES PER OPERATION." << std::endl;
  }

  /**
   * @brief 测试优化版内存池（OptMemPool）
   * 
   * @details 创建优化版内存池实例，初始容量也为512个对象，运行基准测试，
   * 并输出每个操作的平均时钟周期数。使用若干作用域确保内存池对象
   * 在测试完成后被自动释放。
   */
  {
    OptCommon::OptMemPool<Exchange::MDPMarketUpdate> opt_mem_pool(512);
    const auto cycles = benchmarkMemPool(&opt_mem_pool);
    std::cout << "OPTIMIZED MEMPOOL " << cycles << " CLOCK CYCLES PER OPERATION." << std::endl;
  }

  /**
   * @brief 程序成功退出
   * 
   * @details 使用EXIT_SUCCESS状态码表示程序成功执行并正常退出。
   */
  exit(EXIT_SUCCESS);
}
